{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {},
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "d:\\softwares\\python\\lib\\site-packages\\umap\\distances.py:1063: NumbaDeprecationWarning: \u001b[1mThe 'nopython' keyword argument was not supplied to the 'numba.jit' decorator. The implicit default value for this argument is currently False, but it will be changed to True in Numba 0.59.0. See https://numba.readthedocs.io/en/stable/reference/deprecation.html#deprecation-of-object-mode-fall-back-behaviour-when-using-jit for details.\u001b[0m\n",
            "  @numba.jit()\n",
            "d:\\softwares\\python\\lib\\site-packages\\umap\\distances.py:1071: NumbaDeprecationWarning: \u001b[1mThe 'nopython' keyword argument was not supplied to the 'numba.jit' decorator. The implicit default value for this argument is currently False, but it will be changed to True in Numba 0.59.0. See https://numba.readthedocs.io/en/stable/reference/deprecation.html#deprecation-of-object-mode-fall-back-behaviour-when-using-jit for details.\u001b[0m\n",
            "  @numba.jit()\n",
            "d:\\softwares\\python\\lib\\site-packages\\umap\\distances.py:1086: NumbaDeprecationWarning: \u001b[1mThe 'nopython' keyword argument was not supplied to the 'numba.jit' decorator. The implicit default value for this argument is currently False, but it will be changed to True in Numba 0.59.0. See https://numba.readthedocs.io/en/stable/reference/deprecation.html#deprecation-of-object-mode-fall-back-behaviour-when-using-jit for details.\u001b[0m\n",
            "  @numba.jit()\n",
            "d:\\softwares\\python\\lib\\site-packages\\tqdm\\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
            "  from .autonotebook import tqdm as notebook_tqdm\n",
            "d:\\softwares\\python\\lib\\site-packages\\umap\\umap_.py:660: NumbaDeprecationWarning: \u001b[1mThe 'nopython' keyword argument was not supplied to the 'numba.jit' decorator. The implicit default value for this argument is currently False, but it will be changed to True in Numba 0.59.0. See https://numba.readthedocs.io/en/stable/reference/deprecation.html#deprecation-of-object-mode-fall-back-behaviour-when-using-jit for details.\u001b[0m\n",
            "  @numba.jit()\n"
          ]
        }
      ],
      "source": [
        "import numpy as np\n",
        "from bertopic import BERTopic\n",
        "from sentence_transformers import SentenceTransformer\n",
        "from sklearn.feature_extraction.text import CountVectorizer\n",
        "from transformers.pipelines import pipeline\n",
        "from umap import UMAP\n",
        "from hdbscan import HDBSCAN\n",
        "from sklearn.feature_extraction.text import CountVectorizer"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# 加载数据"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "条数:  1000\n",
            "预览第一条:  文旅文 创看 洛阳 河南省 文旅文创 发展 大会 本次 大会 安排 项目 签约 主要 方面 内容 一是 文旅 产业 项目 签约 截至 目前 梳理 重点 文旅 项目 投资总额 525.6 亿元 遴选 重大项目 进行 现场 签约 投资总额 365.8 亿元 项目 包括 文物 数字化 开发 文化 创意 园区 建设 文化 项目 涵盖 旅游 度假区 建设 旅游 酒店 民宿 打造 旅游 项目 既有 旅游 景区 开发 商旅 综合体 建设 传统 业态 项目 宇宙 基地 沉浸 演艺 业态 项目 充分体现 我省 文化 旅游 发展 特点 趋势 二是 引客 入豫 项目 签约 主要 我省 文旅 部门 文旅 企业 头部 旅行 知名 OTA 平台 重点 客源地 文旅 部门 签订 引客 入豫 协议 持续 拓展 省外 客源 市场\n",
            "\n"
          ]
        }
      ],
      "source": [
        "# step1 加载文件\n",
        "with open('../../data/切词.txt', 'r', encoding='utf-8') as file:\n",
        "  docs = file.readlines()\n",
        "print('条数: ', len(docs))\n",
        "print('预览第一条: ', docs[0])\n",
        "\n",
        "vectorizer_model = None"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# 创建"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {},
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "Some weights of the model checkpoint at bert-base-chinese were not used when initializing BertModel: ['cls.predictions.transform.LayerNorm.weight', 'cls.predictions.decoder.weight', 'cls.predictions.transform.dense.weight', 'cls.predictions.transform.dense.bias', 'cls.seq_relationship.weight', 'cls.predictions.transform.LayerNorm.bias', 'cls.seq_relationship.bias', 'cls.predictions.bias']\n",
            "- This IS expected if you are initializing BertModel from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).\n",
            "- This IS NOT expected if you are initializing BertModel from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "(1000, 768)\n"
          ]
        }
      ],
      "source": [
        "# 1. 词向量模型，同时加载本地训练好的词向量\n",
        "embedding_model = pipeline(\"feature-extraction\", model=\"bert-base-chinese\") # 使用bert-base-chinese\n",
        "embeddings = np.load('../../data/embedding_bbc.npy') # 使用bert-base-chinese向量\n",
        "print(embeddings.shape)\n",
        "\n",
        "# 2. 创建分词模型\n",
        "vectorizer_model = CountVectorizer() # 因为我们已经分好词了，所以这里不需要传入分词函数了\n",
        "\n",
        "# 3. 创建UMAP降维模型\n",
        "umap_model = UMAP(\n",
        "  n_neighbors=15,\n",
        "  n_components=5,\n",
        "  min_dist=0.0,\n",
        "  metric='cosine',\n",
        "  random_state=42  # ⚠️ 防止随机 https://maartengr.github.io/BERTopic/faq.html\n",
        ")\n",
        "\n",
        "# 4. 创建HDBSCAN聚类模型\n",
        "# 如果要建设离群值，可以减小下面两个参数\n",
        "# https://hdbscan.readthedocs.io/en/latest/faq.html\n",
        "hdbscan_model = HDBSCAN(\n",
        "  min_cluster_size=40,\n",
        "  min_samples=40,\n",
        ")\n",
        "\n",
        "# 5. 创建CountVectorizer模型\n",
        "vectorizer_model = CountVectorizer(stop_words=['洛阳', '旅游', '文化'])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>Topic</th>\n",
              "      <th>Count</th>\n",
              "      <th>Name</th>\n",
              "      <th>Representation</th>\n",
              "      <th>Representative_Docs</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>-1</td>\n",
              "      <td>501</td>\n",
              "      <td>-1_景区_河南_游客_城市</td>\n",
              "      <td>[景区, 河南, 游客, 城市, 洛阳市, 中国, 历史, 活动, 河南省, 发展]</td>\n",
              "      <td>[河南 多家 景区 陆续 发布 开园 公告 台风 杜苏芮 强度 逐渐 减弱 河南 景区 陆续...</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>0</td>\n",
              "      <td>216</td>\n",
              "      <td>0_中国_石窟_龙门石窟_世界</td>\n",
              "      <td>[中国, 石窟, 龙门石窟, 世界, 艺术, 旅行, 景区, 位于, 河南, 历史]</td>\n",
              "      <td>[龙门石窟 中国 石刻 艺术 宝库 现为 世界 文化遗产 全国 重点 文物保护 单位 国家 ...</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>1</td>\n",
              "      <td>100</td>\n",
              "      <td>1_活动_景区_免费_高速</td>\n",
              "      <td>[活动, 景区, 免费, 高速, 门票, 时间, 白云山, 地点, 期间, 体验]</td>\n",
              "      <td>[洛阳 身边 自驾游 栾川 高速 免费 答疑 自驾游 栾川 高速 费全免 问题 需要 了解 ...</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>2</td>\n",
              "      <td>99</td>\n",
              "      <td>2_发展_城市_项目_河南</td>\n",
              "      <td>[发展, 城市, 项目, 河南, 文旅, 活动, 中国, 国家, 游客, 建设]</td>\n",
              "      <td>[行走 河南 读懂 中国 关注 全省 文旅文创 发展 大会 二十大 报告 指出 坚持 以文塑...</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>3</td>\n",
              "      <td>42</td>\n",
              "      <td>3_地方_很多_一天_时间</td>\n",
              "      <td>[地方, 很多, 一天, 时间, 已经, 一点, 古城, 酒店, 西安, 感受]</td>\n",
              "      <td>[此次 四天 旅行 已经 结束 以往 不用 这次 大学 同学 一起 毕业 一年 小聚 组团 ...</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>5</th>\n",
              "      <td>4</td>\n",
              "      <td>42</td>\n",
              "      <td>4_旅客_郑州_高速_景区</td>\n",
              "      <td>[旅客, 郑州, 高速, 景区, 客流, 出行, 发送, 通行, 假期, 高峰]</td>\n",
              "      <td>[国庆 长假 我市 迎来 客流 高峰 公路 铁路 发送 旅客 超过 万人次 今年 国庆 长假...</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "   Topic  Count             Name                              Representation  \\\n",
              "0     -1    501   -1_景区_河南_游客_城市  [景区, 河南, 游客, 城市, 洛阳市, 中国, 历史, 活动, 河南省, 发展]   \n",
              "1      0    216  0_中国_石窟_龙门石窟_世界  [中国, 石窟, 龙门石窟, 世界, 艺术, 旅行, 景区, 位于, 河南, 历史]   \n",
              "2      1    100    1_活动_景区_免费_高速   [活动, 景区, 免费, 高速, 门票, 时间, 白云山, 地点, 期间, 体验]   \n",
              "3      2     99    2_发展_城市_项目_河南    [发展, 城市, 项目, 河南, 文旅, 活动, 中国, 国家, 游客, 建设]   \n",
              "4      3     42    3_地方_很多_一天_时间    [地方, 很多, 一天, 时间, 已经, 一点, 古城, 酒店, 西安, 感受]   \n",
              "5      4     42    4_旅客_郑州_高速_景区    [旅客, 郑州, 高速, 景区, 客流, 出行, 发送, 通行, 假期, 高峰]   \n",
              "\n",
              "                                 Representative_Docs  \n",
              "0  [河南 多家 景区 陆续 发布 开园 公告 台风 杜苏芮 强度 逐渐 减弱 河南 景区 陆续...  \n",
              "1  [龙门石窟 中国 石刻 艺术 宝库 现为 世界 文化遗产 全国 重点 文物保护 单位 国家 ...  \n",
              "2  [洛阳 身边 自驾游 栾川 高速 免费 答疑 自驾游 栾川 高速 费全免 问题 需要 了解 ...  \n",
              "3  [行走 河南 读懂 中国 关注 全省 文旅文创 发展 大会 二十大 报告 指出 坚持 以文塑...  \n",
              "4  [此次 四天 旅行 已经 结束 以往 不用 这次 大学 同学 一起 毕业 一年 小聚 组团 ...  \n",
              "5  [国庆 长假 我市 迎来 客流 高峰 公路 铁路 发送 旅客 超过 万人次 今年 国庆 长假...  "
            ]
          },
          "execution_count": 4,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "topic_model = BERTopic(\n",
        "  embedding_model=embedding_model,\n",
        "  vectorizer_model=vectorizer_model,\n",
        "  umap_model=umap_model,\n",
        "  hdbscan_model=hdbscan_model,\n",
        ")\n",
        "\n",
        "topics, probs = topic_model.fit_transform(docs, embeddings=embeddings) #传入训练好的词向量\n",
        "topic_info = topic_model.get_topic_info()\n",
        "topic_info"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# 优化主题表示"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>Topic</th>\n",
              "      <th>Count</th>\n",
              "      <th>Name</th>\n",
              "      <th>Representation</th>\n",
              "      <th>Representative_Docs</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>-1</td>\n",
              "      <td>501</td>\n",
              "      <td>-1_洛阳市_河南省_博物馆_郑州</td>\n",
              "      <td>[洛阳市, 河南省, 博物馆, 郑州, 遗址, 老君山, 项目, 河洛, 黄河, 五一]</td>\n",
              "      <td>[河南 多家 景区 陆续 发布 开园 公告 台风 杜苏芮 强度 逐渐 减弱 河南 景区 陆续...</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>0</td>\n",
              "      <td>216</td>\n",
              "      <td>0_龙门石窟_文化遗产_莫高窟_朝代</td>\n",
              "      <td>[龙门石窟, 文化遗产, 莫高窟, 朝代, 龙门, 国家, 少林寺, 洛阳市, 云冈石窟, ...</td>\n",
              "      <td>[龙门石窟 中国 石刻 艺术 宝库 现为 世界 文化遗产 全国 重点 文物保护 单位 国家 ...</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>1</td>\n",
              "      <td>100</td>\n",
              "      <td>1_景区_门票_白云山_栾川</td>\n",
              "      <td>[景区, 门票, 白云山, 栾川, 十一, 线路, 郑州, 攻略, 博物馆, 大峡谷]</td>\n",
              "      <td>[洛阳 身边 自驾游 栾川 高速 免费 答疑 自驾游 栾川 高速 费全免 问题 需要 了解 ...</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>2</td>\n",
              "      <td>99</td>\n",
              "      <td>2_项目_文旅_国家_博物馆</td>\n",
              "      <td>[项目, 文旅, 国家, 博物馆, 接待, 河南省, 企业, 文旅文创, 创新, 栾川]</td>\n",
              "      <td>[行走 河南 读懂 中国 关注 全省 文旅文创 发展 大会 二十大 报告 指出 坚持 以文塑...</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>3</td>\n",
              "      <td>42</td>\n",
              "      <td>3_很多_古城_西安_其实</td>\n",
              "      <td>[很多, 古城, 西安, 其实, 第一次, 最后, 大家, 牛肉汤, 觉得, 晚上]</td>\n",
              "      <td>[此次 四天 旅行 已经 结束 以往 不用 这次 大学 同学 一起 毕业 一年 小聚 组团 ...</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>5</th>\n",
              "      <td>4</td>\n",
              "      <td>42</td>\n",
              "      <td>4_郑州_线路_列车_方向</td>\n",
              "      <td>[郑州, 线路, 列车, 方向, 港澳, 长假, 高速公路, 门票, 铁路, 部分]</td>\n",
              "      <td>[国庆 长假 我市 迎来 客流 高峰 公路 铁路 发送 旅客 超过 万人次 今年 国庆 长假...</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "   Topic  Count                Name  \\\n",
              "0     -1    501   -1_洛阳市_河南省_博物馆_郑州   \n",
              "1      0    216  0_龙门石窟_文化遗产_莫高窟_朝代   \n",
              "2      1    100      1_景区_门票_白云山_栾川   \n",
              "3      2     99      2_项目_文旅_国家_博物馆   \n",
              "4      3     42       3_很多_古城_西安_其实   \n",
              "5      4     42       4_郑州_线路_列车_方向   \n",
              "\n",
              "                                      Representation  \\\n",
              "0       [洛阳市, 河南省, 博物馆, 郑州, 遗址, 老君山, 项目, 河洛, 黄河, 五一]   \n",
              "1  [龙门石窟, 文化遗产, 莫高窟, 朝代, 龙门, 国家, 少林寺, 洛阳市, 云冈石窟, ...   \n",
              "2        [景区, 门票, 白云山, 栾川, 十一, 线路, 郑州, 攻略, 博物馆, 大峡谷]   \n",
              "3       [项目, 文旅, 国家, 博物馆, 接待, 河南省, 企业, 文旅文创, 创新, 栾川]   \n",
              "4         [很多, 古城, 西安, 其实, 第一次, 最后, 大家, 牛肉汤, 觉得, 晚上]   \n",
              "5         [郑州, 线路, 列车, 方向, 港澳, 长假, 高速公路, 门票, 铁路, 部分]   \n",
              "\n",
              "                                 Representative_Docs  \n",
              "0  [河南 多家 景区 陆续 发布 开园 公告 台风 杜苏芮 强度 逐渐 减弱 河南 景区 陆续...  \n",
              "1  [龙门石窟 中国 石刻 艺术 宝库 现为 世界 文化遗产 全国 重点 文物保护 单位 国家 ...  \n",
              "2  [洛阳 身边 自驾游 栾川 高速 免费 答疑 自驾游 栾川 高速 费全免 问题 需要 了解 ...  \n",
              "3  [行走 河南 读懂 中国 关注 全省 文旅文创 发展 大会 二十大 报告 指出 坚持 以文塑...  \n",
              "4  [此次 四天 旅行 已经 结束 以往 不用 这次 大学 同学 一起 毕业 一年 小聚 组团 ...  \n",
              "5  [国庆 长假 我市 迎来 客流 高峰 公路 铁路 发送 旅客 超过 万人次 今年 国庆 长假...  "
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "from bertopic.representation import MaximalMarginalRelevance # 导入\n",
        "# diversity: How diverse the select keywords/keyphrases are.\n",
        "#                     Values range between 0 and 1 with 0 being not diverse at all\n",
        "#                     and 1 being most diverse.\n",
        "representation_model = MaximalMarginalRelevance(diversity=0.3) # 创建mmr模型\n",
        "topic_model = BERTopic(\n",
        "  embedding_model=embedding_model,\n",
        "  vectorizer_model=vectorizer_model,\n",
        "  umap_model=umap_model,\n",
        "  hdbscan_model=hdbscan_model,\n",
        "  representation_model=representation_model # 传入模型\n",
        ")\n",
        "\n",
        "topics, probs = topic_model.fit_transform(docs, embeddings=embeddings)\n",
        "topic_info = topic_model.get_topic_info()\n",
        "topic_info"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.10.6"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 2
}
